package studio.raptor.hub.in;

import com.ai.aif.csf.client.service.factory.CsfServiceFactory;
import com.ai.aif.csf.client.service.interfaces.IClientSV;
import com.ai.aif.csf.common.constants.CsfConstants;
import com.alibaba.fastjson.JSON;
import com.google.common.base.Preconditions;
import java.io.UnsupportedEncodingException;

import java.util.HashMap;
import java.util.Map;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHeader;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import studio.raptor.hub.common.exception.HubInException;
import studio.raptor.hub.in.constant.HubInServerTypes;
import studio.raptor.hub.in.entity.ServerProxyReq;


public abstract class ServerProxy {

  private static final Logger log = LoggerFactory.getLogger(ServerProxy.class);
  private HttpClient httpClient;
  private String serverUrl;
  private String message;
  private String hubInServerType;

  public ServerProxy(HttpClient httpClient) {
    this.httpClient = httpClient;
  }


  public String queryServerMsg(ServerProxyReq serverProxyReq) throws Exception {
    this.serverUrl = serverProxyReq.getUrl();
    this.hubInServerType = serverProxyReq.getServerType();
    this.message = getMessage(serverProxyReq.getParams());
    if (log.isDebugEnabled()) {
      log.debug("serverProxyReq url->{} ,params->{} ,serverType->{}, message->{}",
          new Object[]{serverProxyReq.getUrl(), serverProxyReq.getParams(),
              serverProxyReq.getServerType(), this.message});
    }

    String response = "";
    Preconditions.checkArgument(null != serverProxyReq.getServerType(), "serverType cannot empty!");
    switch (hubInServerType) {
      case HubInServerTypes.HTTP:
        Preconditions.checkArgument(null != httpClient, "httpClient cannot empty!");
        response = queryMsgByHttp();
        break;
      case HubInServerTypes.CSF:
        response = queryMsgByCsf();
        break;
      default:
        throw new HubInException("hub in not support type " + hubInServerType);
    }

    log.debug("response data " + response);

    String jsonResult = handleResponse(response);
    if (log.isDebugEnabled()) {
      log.debug("ServerProxy Server->{} ,jsonResult->{}", new Object[]{serverUrl, jsonResult});
    }
    return jsonResult;
  }

  protected abstract String handleResponse(String response);

  protected abstract String getMessage(Long... params);

  private String queryMsgByHttp() throws Exception {
    HttpPost request = this.buildRequest(serverUrl, message);
    HttpResponse httpResponse = this.httpClient.execute(request);
    String response = EntityUtils.toString(httpResponse.getEntity(), HTTP.UTF_8);
    int code = httpResponse.getStatusLine().getStatusCode();
    if (code != HttpStatus.SC_OK) {
      throw new HubInException(serverUrl + "服务异常！");
    } else {
      if (log.isDebugEnabled()) {
        log.debug("send serverUrl -> {},message -> {},response->{}",
            new Object[]{serverUrl, message, response});
      }
      return response;
    }
  }

  private String queryMsgByCsf() throws Exception {
    Map<String,Object> reqParam = new HashMap<>();
    if (this.message.startsWith("[")) {
      this.message = this.message.substring(1, this.message.length() - 1);
    }
    String[] messages = new String[]{ this.message };
    reqParam.put("var_protocol", "json_object");
    reqParam.put(CsfConstants.SingleParamRequestKey.VAR_REQUET_KEY, messages);
    IClientSV client = CsfServiceFactory.getService(this.serverUrl);
    Object resultObject = client.service(reqParam);
    String response = resultObject.toString();
    return response;
  }

  private HttpPost buildRequest(String url, String message) throws UnsupportedEncodingException {
    StringEntity entity = new StringEntity(message);
    HttpPost request = new HttpPost(url);
    request.setEntity(entity);
    Header header = new BasicHeader("Content-Type", "text/xml;charset=UTF-8");
    request.setHeader(header);
    return request;
  }
}
